/**
 * @author Clark
 * @email haixuanwoTxh@gmail.com
 * @date 2021-10-23
 */

#include "talkprotocol.h"
#include <stdio.h>
#include <string.h>
#include <QDebug>

/**
 * @brief 以十六进制打印
 * @param data	数据
 * @param dataLen 数据长度
 */
void TalkProtocol::print_data_as_hex(unsigned char *data, int dataLen)
{
    char *buf = new char[dataLen*3 + 1];

    int i = 0;
    for(i = 0; i < dataLen; i++)
    {
        snprintf(buf + i*3, 4, "%02x ", data[i]);
    }

    qDebug()<<"Data Len["<<dataLen<<"]:"<<buf;
    delete[] buf;
}

/**
 * @brief 设置数值到2字节空间
 * @param value 数值
 * @param buf 设置的地址
 */
void TalkProtocol::set_value_to_2Byte_buf(unsigned short value, unsigned char *buf)
{
    buf[1] = value&0xFF;
    buf[0] = value>>8 & 0xFF;
}

/**
 * @brief 获取2字节空间中的数值
 * @param  buf 获取的地址
 * @param  value 获取的数值
 */
void TalkProtocol::get_value_from_2Byte_buf(unsigned char *buf, unsigned short &value)
{
    value  = buf[0]*0x100 + buf[1];
}

/**
 * @brief 设置数值到4字节空间
 * @param value 设置的数值
 * @param buf 设置地址
 */
void TalkProtocol::set_value_to_4Byte_buf(unsigned int value, unsigned char *buf)
{
    buf[3] = value&0xFF;
    buf[2] = value>>8 & 0xFF;
    buf[1] = value>>16 & 0xFF;
    buf[0] = value>>24 & 0xFF;
}

/**
 * @brief 获取4字节空间中的数值
 * @param  buf 获取地址
 * @param  value 获取的数值
 */
void TalkProtocol::get_value_from_4Byte_buf(unsigned char *buf, unsigned int &value)
{
    value = buf[0]*0x1000000 + buf[1]*0x10000 + buf[2]*0x100 + buf[3];
}

/**
 * @brief 获取校验码，数据的字节累加和
 * @param data 		数据
 * @param dataLen	数据长度
 * @param checksum	校验码结果
 * @return true		成功
 * @return false	失败
 */
bool TalkProtocol::get_checksum(unsigned char *data, int dataLen, unsigned short &checksum)
{
    if (nullptr == data || dataLen <= 0)
    {
        qDebug()<<"get checksum param error";
        return false;
    }

    checksum = 0;
    for (int i = 0; i < dataLen; i++)
    {
        checksum += data[i];
    }

    return true;
}

/**
 * @brief 构建协议包
 * @param action  	包行为类型
 * @param data		包数据
 * @param dataLen	数据长度
 * @param packet	存放数据包的缓存
 * @param packetBufSize	缓存空间大小
 * @param packetLen	包大小
 * @return true		成功
 * @return false	失败
 */
bool TalkProtocol::build_protocol_packet(Action action, unsigned char* data, int dataLen, unsigned char* packet, int packetBufSize, int &packetLen)
{
    int index = 0;
    unsigned short checksum = 0;

    if (nullptr == data || dataLen < 0 || nullptr == packet)
    {
        qDebug()<<"build protocol packet para error";
        return false;
    }

    packetLen = dataLen + BASIC_PACKET_LEN;
    if (packetLen > packetBufSize)
    {
        qDebug()<<__func__<<" error packetLen > packetBufSize";
        return false;
    }

    // 包头
    set_value_to_2Byte_buf(HEAD, packet);
    index += 2;

    // 消息行为
    set_value_to_2Byte_buf(action, packet + index);
    index += 2;

    // 数据长度
    set_value_to_2Byte_buf(dataLen, packet + index);
    index += 2;

    // 数据
    memcpy(packet + index, data, dataLen);
    index += dataLen;

    // checksum
    set_value_to_2Byte_buf(0, packet + index);
    if (false == get_checksum(packet+2, index-2, checksum))
    {
        printf("build packet get checksum error\n");
        return false;
    }

    set_value_to_2Byte_buf(checksum, packet + index);
    index += 2;

    // 包尾
    set_value_to_2Byte_buf(END, packet + index);
    index += 2;

    if (index != packetLen)
    {
        printf("index[%d] packetLen[%d] error\n", index, packetLen);
        return false;
    }

    return true;
}

/**
 * @brief 解析协议包
 * @param packet	包内容
 * @param packetLen	包长度
 * @param action	解析出的包行为类型
 * @param data		解析出的数据
 * @param dataBufSize	存储数据缓存大小
 * @param dataLen	数据长度
 * @return true		成功
 * @return false	失败
 */
bool TalkProtocol::parse_protocol_packet(unsigned char* packet, int packetLen, Action &action, unsigned char* data, int dataBufSize, int &dataLen)
{
    if (nullptr == packet || packetLen < BASIC_PACKET_LEN || nullptr == data)
    {
        printf("parse packet param error\n");
        return false;
    }

    int index = 0;

    // 包头
    unsigned short head = 0;
    get_value_from_2Byte_buf(packet, head);
    if(HEAD != head)
    {
        printf("parse packet head error\n");
        return false;
    }
    index += 2;

    // 行为类型
    unsigned short getAction = 0;
    get_value_from_2Byte_buf(packet + index, getAction);
    action = (Action )getAction;
    index += 2;

    // 数据长度
    unsigned short len = 0;
    get_value_from_2Byte_buf(packet + index, len);
    dataLen = len;
    if (dataLen > packetLen - BASIC_PACKET_LEN)
    {
        printf("parse packet dataLen error\n");
        return false;
    }

    if (dataLen > dataBufSize)
    {
        printf("parse packet dataLen[%d] > dataBufSize[%d] error\n", dataLen, dataBufSize);
        return false;
    }
    index += 2;

    // 数据
    memcpy(data, packet + index, dataLen);
    index += dataLen;

    // 检验码
    unsigned short checksum = 0;
    get_value_from_2Byte_buf(packet + index, checksum);
    // set_value_to_2Byte_buf(0, packet + index);

    unsigned short checksumCount = 0;
    if (false == get_checksum(packet+2, index-2, checksumCount))
    {
        printf("parse packet get checksum error\n");
        return false;
    }

    if (checksum != checksumCount)
    {
        printf("parse packet checksum[%04x] checksumCount[%04x] error\n", checksum, checksumCount);
        return false;
    }
    index += 2;

    // 包尾
    unsigned short end = 0;
    get_value_from_2Byte_buf(packet+index, end);
    if (END != end)
    {
        printf("parse packet end error\n");
        return false;
    }
    index += 2;

    if (index != packetLen)
    {
        printf("parse packet index[%d] != packetLen[%d] error\n", index, packetLen);
        return false;
    }

    return true;
}

/**
 * @brief 从数据中获取用户名和密码
 * @param data		数据
 * @param dataLen	数据长度
 * @param user		用户名
 * @param passwd	密码
 * @return true		成功
 * @return false	失败
 */
bool TalkProtocol::get_name_passwd(unsigned char *data, int dataLen, std::string &user, std::string &passwd)
{
    int index = 0;
    unsigned short int userLen = 0;
    char userData[USR_MAX_LEN] = {0};
    unsigned short int passwdLen = 0;
    char passwdData[PASSWD_MAX_LEN] = {0};

    if (nullptr == data || dataLen < 6)
    {
        std::cout<<"data or dataLen error"<<std::endl;
        return false;
    }

    get_value_from_2Byte_buf(data, userLen);
    if (userLen > USR_MAX_LEN)
    {
        std::cout<<"user len["<<userLen<<"] error"<<std::endl;
    }
    index += 2;

    memcpy(userData, data + index, userLen);
    index += userLen;

    get_value_from_2Byte_buf(data + index, passwdLen);
    if (passwdLen > USR_MAX_LEN)
    {
        std::cout<<"passwd len["<<passwdLen<<"] error"<<std::endl;
    }
    index += 2;

    memcpy(passwdData, data + index, passwdLen);
    index += passwdLen;

    if (index != dataLen)
    {
        std::cout<<"dataLen["<<dataLen<<"] error"<<std::endl;
        return false;
    }

    user = userData;
    passwd = passwdData;

    return true;
}

/**
 * @brief set用户名和密码
 * @param user		用户名
 * @param passwd	密码
 * @param data		数据
 * @param dataBufSize
 * @param dataLen	数据长度
 * @return true		成功
 * @return false	失败
 */
bool TalkProtocol::set_user_passwd(QString &user, QString &passwd, unsigned char *data, int dataBufSize, int &dataLen)
{
    int index = 0;
    int len = user.length() + passwd.length() + 4;

    if (user.length() == 0 || passwd.length() == 0 || nullptr == data || len > dataBufSize)
    {
        printf("set user passwd error\n");
        return false;
    }

    set_value_to_2Byte_buf(user.length(), data);
    index += 2;

    memcpy(data + index, user.toLatin1().data(), user.length());
    index += user.length();

    set_value_to_2Byte_buf(passwd.length(), data + index);
    index += 2;

    memcpy(data + index, passwd.toLatin1().data(), passwd.length());
    index += passwd.length();

    dataLen = index;

    return true;
}

/**
 * @brief get complete protocol packet
 * @param data		数据
 * @param dataLen	数据长度
 * @param packetStart 包起始位
 * @param packetLen 包长度
 * @return 0 成功获取到完整包, 1 获取到不完整包, 2 当前数据不能做出判断, -1 获取的数据不够最小包长了
 */
int TalkProtocol::get_complete_protocol_packet(unsigned char *data, int dataLen,int &packetStart, int &packetLen)
{
    int index = 0;

    if (nullptr == data || dataLen < BASIC_PACKET_LEN)
    {
        qDebug()<<"get complete protocol paket fail";
        return 2;
    }

    for (int start = 0; start < dataLen - BASIC_PACKET_LEN + 1; start++)
    {
        index = start;
        // 1 find head
        if (0xFF != data[index] || 0xFF != data[index + 1])
        {
            continue;
        }
        index += 2;

        // 2 judge action
        unsigned short action = INVALID_ACTION;
        get_value_from_2Byte_buf(data+index, action);
        if (action >= INVALID_ACTION)
        {
            continue;
        }
        index += 2;

        // 3 get packet len, judge is enough len of complete
        unsigned short packetDataLen = 0;
        get_value_from_2Byte_buf(data+index, packetDataLen);
        if (packetDataLen > dataLen - index - 4)
        {
            packetStart = start; // 数据不足不构成完整包
            qDebug()<<"Get uncomplete packert start:"<<start;
            return 1;
        }
        index += (2 + packetDataLen);

        // 4 checksum
        unsigned short checksum = 0;
        get_value_from_2Byte_buf(data+index, checksum);

        unsigned short checksumCount = 0;
        if (false == get_checksum(data+start+2, index-start-2, checksumCount))
        {
            qDebug()<<"parse packet get checksum error\n";
            continue;
        }

        if (checksum != checksumCount)
        {
            qDebug()<<"parse packet checksum["<<checksum<<"] checksumCount["<<checksumCount<<"] error";
            continue;
        }
        index += 2;

        // 5 包尾
        unsigned short end = 0;
        get_value_from_2Byte_buf(data+index, end);
        if (END != end)
        {
            qDebug()<<"parse packet end error";
            continue;
        }
        index += 2;

        packetStart = start;            // 包起始位置
        packetLen = index - start;      // 完整包长
        return 0;
    }

    return -1;
}
